package data;

import constants.MuleTypes;

import javax.swing.*;

/**
 * @author Ivan Jimenez
 * @version 11/5/13
 */
public class Shopping {

	/**
	 * Attempts to make player buy the amount of food from the store
	 *
	 * @param player player that will buy food
	 * @param store  current game store that will sell food
	 * @param amount the amount of food in question
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerBuysFood(Player player, Store store, int amount) {
		boolean storeHasStock = store.getFoodStock() < amount;
		boolean playerHasMoney = player.makePurchase(amount * store.getFoodPrice());

		if (storeHasStock || !playerHasMoney) {
			return false;
		}
		player.addFood(store.sellFood(amount * store.getFoodPrice()));
		return true;
	}

	/**
	 * Attempts to make player buy the amount of ore from the store
	 *
	 * @param player player that will buy ore
	 * @param store  current game store that will sell ore
	 * @param amount the amount of ore in question
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerBuysOre(Player player, Store store, int amount) {
		boolean storeHasStock = store.getOreStock() < amount;
		boolean playerHasMoney = player.makePurchase(amount * store.getOrePrice());

		if (storeHasStock || !playerHasMoney) {
			return false;
		}
		player.addOre(store.sellOre(amount * store.getOrePrice()));
		return true;
	}

	/**
	 * Attempts to make player buy the amount of energy from the store
	 *
	 * @param player player that will buy energy
	 * @param store  current game store that will sell energy
	 * @param amount the amount of energy in question
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerBuysEnergy(Player player, Store store, int amount) {
		boolean storeHasStock = store.getEnergyStock() < amount;
		boolean playerHasMoney = player.makePurchase(amount * store.getEnergyPrice());

		if (storeHasStock || !playerHasMoney) {
			return false;
		}
		player.addEnergy(store.sellEnergy(amount * store.getEnergyPrice()));
		return true;
	}

	/**
	 * Attempts to make player buy the amount of crystite from the store
	 *
	 * @param player player that will buy crystite
	 * @param store  current game store that will sell crystite
	 * @param amount the amount of crystite in question
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerBuysCrystite(Player player, Store store, int amount) {
		boolean storeHasStock = store.getCrystiteStock() < amount;
		boolean playerHasMoney = player.makePurchase(amount * store.getCrystitePrice());

		if (storeHasStock || !playerHasMoney) {
			return false;
		}
		player.addCrystite(store.sellCrystite(amount * store.getCrystitePrice()));
		return true;
	}

	/**
	 * Attempts to make player buy a mule from the store
	 *
	 * @param player that will buy mule
	 * @param store  current game store that will sell mule
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerBuysMule(Player player, Store store) {
		boolean noStock = store.getMuleStock() < MULE.MAX_MULE_NUM;
		boolean playerHasMoney = player.makePurchase(Store.costOfMule);

		if (noStock || player.hasFreeMule() || !playerHasMoney) {
			return false;
		}
		String[] selectionValues = {"Food - 25", "Ore - 75", "Energy - 50", "Crystite - 100"};
		String choice = (String) JOptionPane.showInputDialog(null, "Choose Mule OutFitting", "Input",
				JOptionPane.INFORMATION_MESSAGE, null, selectionValues, selectionValues[0]);

		boolean canAdd = false;
		MuleTypes newMuleOutfit = MuleTypes.CRYSTITE;
		switch (choice) {
			case "Food - 25":
				if (player.getMoney() >= 25) {
					player.addMoney(-25);
					newMuleOutfit = MuleTypes.FOOD;
					canAdd = true;
				} else {
					JOptionPane.showMessageDialog(null, "You do not have enough money");
				}
				break;
			case "Ore - 75":
				if (player.getMoney() > 75) {
					player.addMoney(-75);
					newMuleOutfit = MuleTypes.ORE;
					canAdd = true;
				} else {
					JOptionPane.showMessageDialog(null, "You do not have enough money");
				}
				break;
			case "Crystite - 100":
				if (player.getMoney() >= 100) {
					player.addMoney(-100);
					newMuleOutfit = MuleTypes.CRYSTITE;
					canAdd = true;
				} else {
					JOptionPane.showMessageDialog(null, "You do not have enough money");
				}
				break;
			default:
				if (player.getMoney() >= 50) {
					player.addMoney(-50);
					newMuleOutfit = MuleTypes.ENERGY;
					canAdd = true;
				} else {
					JOptionPane.showMessageDialog(null, "You do not have enough money");
				}
				break;
		}
		if (canAdd) {
			player.addFreeMule(new MULE(newMuleOutfit));
			store.sellMule();
		}
		return true;
	}

	/**
	 * Attempts to make a player sell the amount of food to the store
	 *
	 * @param player player that will sell food to the store
	 * @param store  current game store to which player will sell food
	 * @param amount the amount of food to be transacted
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerSellsFood(Player player, Store store, int amount) {
		boolean storeHasMoney = store.hasMoney(store.getFoodPrice() * amount);
		boolean playerHasFood = player.decrementFood(amount);

		if (!storeHasMoney || !playerHasFood) {
			return false;
		}
		player.addMoney(store.buyFood(amount));
		return true;
	}

	/**
	 * Attempts to make the player sell the amount of ore to the store
	 *
	 * @param player player that will sell ore to the store
	 * @param store  current game store to which player will sell ore
	 * @param amount the amount of ore to be transacted
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerSellsOre(Player player, Store store, int amount) {
		boolean storeHasMoney = store.hasMoney(store.getOrePrice() * amount);
		boolean playerHasOre = player.decrementOre(amount);

		if (!storeHasMoney || !playerHasOre) {
			return false;
		}
		player.addMoney(store.buyOre(amount));
		return true;
	}

	/**
	 * Attempts to make the player sell the amount of energy to the store
	 *
	 * @param player player that will sell energy to the store
	 * @param store  current game store to which player will sell energy
	 * @param amount the amount of energy to be transacted
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerSellsEnergy(Player player, Store store, int amount) {
		boolean storeHasMoney = store.hasMoney(store.getEnergyPrice() * amount);
		boolean playerHasEnergy = player.decrementEnergy(amount);

		if (!storeHasMoney || !playerHasEnergy) {
			return false;
		}
		player.addMoney(store.buyEnergy(amount));
		return true;
	}

	/**
	 * Attempts to make the player sell the amount of crystite to the store
	 *
	 * @param player player that will sell crystite to the store
	 * @param store  current game store to which player will sell crystite
	 * @param amount the amount of crystite to be transacted
	 * @return false if transaction successful; true otherwise
	 */
	public static boolean playerSellsCrystite(Player player, Store store, int amount) {
		boolean storeHasMoney = store.hasMoney(store.getCrystitePrice() * amount);
		boolean playerHasCrystite = player.decrementCrystite(amount);

		if (!storeHasMoney || !playerHasCrystite) {
			return false;
		}
		player.addMoney(store.buyCrystite(amount));
		return true;
	}

	/**
	 * Attempts to make the player buy the amounts of food, ore and energy specified
	 * Also attempts to buy a mule if the flag is set
	 *
	 * @param player   the player that wishes to make a purchase
	 * @param store    the current game store from which the player wishes to make a purchase
	 * @param food     the amount of food to be bought by the player
	 * @param ore      the amount of ore to be bought by the player
	 * @param energy   the amount of energy to be bought by the player
	 * @param crystite the amount of crystite to be bought by the player
	 * @param MULE     true if the player wishes to buy a mule, false otherwise
	 */
	public static void PlayerMakesPurchase(Player player, Store store,
	                                       int food, int ore, int energy, int crystite, boolean MULE) {
		boolean foodProblems = !playerBuysFood(player, store, food);
		boolean oreProblems = !playerBuysOre(player, store, ore);
		boolean energyProblems = !playerBuysEnergy(player, store, energy);
		boolean crystiteProblems = !playerBuysCrystite(player, store, crystite);
		boolean muleProblems = false;

		if (MULE) {
			muleProblems = !playerBuysMule(player, store);
		}

		if (foodProblems || oreProblems || energyProblems || muleProblems || crystiteProblems) {
			String errorMessage = String.format("Fatal Error, the Application Must Close. " +
					"Attempt to make invalid purchase. For Debugging:\n" +
					"foodProblems: %b, oreProblems: %b, energyProblems: %b, muleProblems: %b",
					foodProblems, oreProblems, energyProblems, muleProblems);

			JOptionPane.showMessageDialog(null, errorMessage, "fatal error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
	}

	/**
	 * Attempts to make player sell the amounts of food, ore and energy to the store
	 *
	 * @param player   the player that wishes to make a sale
	 * @param store    the current game store to which the player wishes to make a sale
	 * @param food     the amount of food to be sold by the player
	 * @param ore      the amount of ore to be sold by the player
	 * @param energy   the amount of energy to be sold by the player
	 * @param crystite the amount of crystite to be sold by the player
	 */
	public static void PlayerMakesSale(Player player, Store store, int food, int ore,
	                                   int energy, int crystite) {
		boolean foodProblems = !playerSellsFood(player, store, food);
		boolean oreProblems = !playerSellsOre(player, store, ore);
		boolean energyProblems = !playerSellsEnergy(player, store, energy);
		boolean crystiteProblems = !playerSellsCrystite(player, store, crystite);

		if (foodProblems || oreProblems || energyProblems || crystiteProblems) {
			String errorMessage = String.format("Fatal Error, the Application Must Close. " +
					"Attempt to make invalid purchase. For Debugging:\n" +
					"foodProblems: %b, oreProblems: %b, energyProblems: %b",
					foodProblems, oreProblems, energyProblems);
			JOptionPane.showMessageDialog(null, errorMessage, "fatal error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
	}

	/**
	 * Checks whether the player can buy the specified amounts of food, ore and energy
	 * if the Mule flag is set, also checks if the player can buy a mule
	 *
	 * @param player   the player that wishes to make a purchase
	 * @param store    the current game store from which the player wishes to make a purchase
	 * @param food     the amount of food to be bought by the player
	 * @param ore      the amount of ore to be bought by the player
	 * @param energy   the amount of energy to be bought by the player
	 * @param crystite the amount of crystite to be bought by the player
	 * @param MULE     true if the player wishes to buy a mule, false otherwise
	 * @return true iff can buy specified amounts (and mule)
	 */
	public static boolean PlayerCanMakePurchase(Player player, Store store,
	                                            int food, int ore, int energy, int crystite, boolean MULE) {
		int costOfFood = store.getFoodPrice() * food;
		int costOfOre = store.getOrePrice() * ore;
		int costOfEnergy = store.getEnergyPrice() * energy;
		int costOfCrystite = store.getCrystitePrice() * crystite;

		int totalCost = costOfFood + costOfEnergy + costOfOre + costOfCrystite;

		boolean storeHasStock = store.hasFood(food) && store.hasOre(ore) &&
				store.hasEnergy(energy) && store.hasCrystite(crystite);

		if (MULE) {
			totalCost += Store.costOfMule;
			storeHasStock = storeHasStock && store.hasMULE();
			return storeHasStock && !player.hasFreeMule() && player.hasMoney(totalCost);
		}
		return storeHasStock && player.hasMoney(totalCost);
	}

	/**
	 * Checks whether the player can sell the specified amounts of food, ore and energy to the store
	 *
	 * @param player   the player that wishes to make a sale
	 * @param store    the current game store to which the player wishes to make a sale
	 * @param food     the amount of food to be sold by the player
	 * @param ore      the amount of ore to be sold by the player
	 * @param energy   the amount of energy to be sold by the player
	 * @param crystite the amount of crystite to be sold by the player
	 * @return true iff player can sell those amounts
	 */
	public static boolean PlayerCanMakeSale(Player player, Store store, int food, int ore,
	                                        int energy, int crystite) {
		int costOfFood = store.getFoodPrice() * food;
		int costOfOre = store.getOrePrice() * ore;
		int costOfEnergy = store.getEnergyPrice() * energy;
		int costOfCrystite = store.getCrystitePrice() * crystite;
		int totalCost = costOfEnergy + costOfFood + costOfOre + costOfCrystite;

		boolean playerHasStock = player.hasEnergy(energy) && player.hasOre(ore) &&
				player.hasFood(food) && player.hasCrystite(crystite);

		return playerHasStock && store.hasMoney(totalCost);
	}
}
